<?php declare(strict_types=1);
/**
 * @author      guosir
 * @copyright   2023-2025 owner
 **/

namespace Srv\Apps\Apis\Account;

use Srv\Apps\Apis\Account\Ctl\AccountCtl;
use Srv\Apps\Apis\Log\Ctl\LogCtl;
use Srv\Apps\Proto\DTO\Account\SignInAccountPassDTO;
use Srv\Apps\Proto\Enum\ErrCodeEnum;
use Srv\Apps\Proto\Enum\LangKeyEnum;
use Srv\Apps\Proto\Enum\Log\LogResultEnum;
use Srv\Apps\Proto\VO\Account\SignInAdmUserVO;
use Srv\Apps\Proto\VO\Account\SignInVerifyCodeVO;
use Srv\Apps\Proto\VO\Account\SignInVO;
use Srv\Apps\Proto\VO\TokenVO;
use Srv\Libs\ConfModel\RouteConfData;
use Srv\Libs\Frame\ActionAbstract;
use Srv\Libs\Frame\AuthData;
use Srv\Libs\Frame\DTOAbstract;
use Srv\Libs\Frame\Lang;
use Srv\Libs\Frame\RequestHeader;
use Srv\Libs\Frame\ResponseData;
use Srv\Libs\Frame\VOAbstract;

final class AccountAct extends ActionAbstract
{
    /**
     * @url /acc/signin/account/pass
     * @auth NULL
     * @req Srv.Apps.Proto.DTO.Account.SignInAccountPassDTO
     * @rsp Srv.Apps.Proto.VO.Account.SignInVO
     * 登入[帐号+密码]
     */
    public function signInAccountPass(RouteConfData $RouteConfData, ?DTOAbstract $DTOClass, ?VOAbstract $VOClass):bool
    {
        unset($RouteConfData);
        if(!($DTOClass instanceof SignInAccountPassDTO) || !($VOClass instanceof SignInVO)) return ResponseData::rspErrAuto(ErrCodeEnum::ERR_SYS_PARAMS_ERROR, Lang::get(LangKeyEnum::LANG_SYS_PARAMS_ERROR));
        $AccountCtl             = AccountCtl::tag();
        $SignInAdmUserVO        = new SignInAdmUserVO();
        $account                = $DTOClass->getAccount();
        $password               = $DTOClass->getPassword();
        $verifyCode             = $DTOClass->getVerifyCode();
        $devId                  = RequestHeader::getDevId();
        $LogCtl                 = LogCtl::tag();
        $logData                = ['acc' => $account, 'pwd' => $password, 'verifyCode' => $verifyCode, 'devId' => $devId];
        if(!$AccountCtl->checkSignInCode($devId, $verifyCode)){
            $errMsg             = '验证码失效';
            $LogCtl->logAdd(LogCtl::SIGN_IN_ACCOUNT_PASS, LogResultEnum::LOG_RESULT_FAIL, $errMsg, $logData);
            return ResponseData::rspErrAuto(ErrCodeEnum::LANG_VERIFY_CODE_ERROR, Lang::get(LangKeyEnum::LANG_VERIFY_CODE_ERROR));
        }
        $errCode                = 0;
        $admUserId              = $AccountCtl->signInAccountPass($account, $password, $SignInAdmUserVO, $errCode);
        $errMsg                 = '';
        if($errCode > 0){
            switch ($errCode){
                case 1:
                    $errMsg     = Lang::get(LangKeyEnum::LANG_SIGN_IN_PARAMS_ERROR);
                    break;
                case 2:
                case 3:
                    $errMsg     = Lang::get(LangKeyEnum::LANG_SIGN_IN_PASSWORD_ERROR);
                    break;
                case 4:
                    $errMsg     = Lang::get(LangKeyEnum::LANG_SIGN_IN_FORBIDDEN_ERROR);
                    break;
            }
            $LogCtl->logAdd(LogCtl::SIGN_IN_ACCOUNT_PASS, LogResultEnum::LOG_RESULT_FAIL, $errMsg, $logData);
            return ResponseData::rspErrAuto(ErrCodeEnum::ERR_FAIL, $errMsg);
        }
        // 登入令牌
        $appPlatform            = RequestHeader::getAppPlatform();
        $devId                  = RequestHeader::getDevId();
        $TokenVO                = null;
        $nonceInt               = 0;
        if(!$AccountCtl->signInUserId($admUserId, $devId, $appPlatform, $TokenVO, $nonceInt) || !($TokenVO instanceof TokenVO) || !AuthData::init($TokenVO->getTokenStr(), $devId, $appPlatform) || AuthData::getLoginUserId() < 1){
            $errMsg             = '登入失败';
            $LogCtl->logAdd(LogCtl::SIGN_IN_ACCOUNT_PASS, LogResultEnum::LOG_RESULT_FAIL, $errMsg, $logData);
            return ResponseData::rspErrAuto(ErrCodeEnum::ERR_FAIL, Lang::get(LangKeyEnum::LANG_FAILED));
        }
        $VOClass->setTokenData($TokenVO);
        $VOClass->setTokenUser($SignInAdmUserVO);
        $errMsg                 = '登入成功';
        $LogCtl->logAdd(LogCtl::SIGN_IN_ACCOUNT_PASS, LogResultEnum::LOG_RESULT_SUCCESS, $errMsg, $logData);
        return ResponseData::rspSuccAuto('', $VOClass, []);
    }

    /**
     * @url /acc/signin/account/code
     * @auth NULL
     * @rsp Srv.Apps.Proto.VO.Account.SignInVerifyCodeVO
     * 获取账号登入验证码
     */
    public function getSignInCode(RouteConfData $RouteConfData, ?DTOAbstract $DTOClass, ?VOAbstract $VOClass):bool
    {
        unset($RouteConfData, $DTOClass);
        if(!($VOClass instanceof SignInVerifyCodeVO)) return ResponseData::rspErrAuto(ErrCodeEnum::ERR_SYS_PARAMS_ERROR, Lang::get(LangKeyEnum::LANG_SYS_PARAMS_ERROR));
        $devId                  = RequestHeader::getDevId();
        $LogCtl                 = LogCtl::tag();
        $logData                = ['devId' => $devId];
        $limitKey               = $devId.'getSignInCode';
        $limitTime              = 10;
        $limitNum               = 5;
        if(!$this->limitSpeed($limitKey, $limitTime, $limitNum)){
            $errMsg             = '请求过于频繁';
            $LogCtl->logAdd(LogCtl::SIGN_IN_ACCOUNT_CODE, LogResultEnum::LOG_RESULT_FAIL, $errMsg, $logData);
            return ResponseData::rspErrAuto(ErrCodeEnum::ERR_FAIL, Lang::get(LangKeyEnum::LANG_SYS_LIMIT_ERROR));
        }
        $CodeValue              = '';
        if(!AccountCtl::tag()->getSignInCode($devId, $VOClass, $CodeValue)){
            $errMsg             = '获取验证码失败';
            $LogCtl->logAdd(LogCtl::SIGN_IN_ACCOUNT_CODE, LogResultEnum::LOG_RESULT_FAIL, $errMsg, $logData);
            return ResponseData::rspErrAuto(ErrCodeEnum::ERR_FAIL, Lang::get(LangKeyEnum::LANG_FAILED));
        }
        $errMsg                 = '获取验证码成功';
        $logData['verifyCode']  = $CodeValue;
        $LogCtl->logAdd(LogCtl::SIGN_IN_ACCOUNT_CODE, LogResultEnum::LOG_RESULT_SUCCESS, $errMsg, $logData);
        return ResponseData::rspSuccAuto('', $VOClass, []);
    }
}